/*
题意：一个A*B的地图中，有若干个机器人，经过若干步操作，若机器人没有发生碰撞或者走出地图（就是碰到地图的边界）就输出OK，
如果机器人走出地图输出"Robot 1 crashes into the wall"其中1为走出边界的机器人的编号；
如果两个机器人相撞则输出"Robot 1 crashes into robot 2"表示机器人1撞了机器人2.
输入：
第一行为T;代表有T组数据，
第二行有两个数，代表地图的大小A*B，
第三行有两个数，分别代表机器人的数量n和操作指令的数目m。
4到n+4行代表n个机器人的位置和行动的方向。
n+5行到n+5+m为操作指令。输入结束。
注意：并不是所有的机器人同时行动，而是根据操作指令一步一步的进行。

操作指令有三种：向左转向，向右转向，向前移动，转向的时候根据给定的转动次数进行转向，每一次转动90度
*/
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <stack>
#define ll long long
#define PI acos(-1)
#define mem(n, m) memset(n, m, sizeof(n));
const int INF = 1e9 + 7;
const int maxn = 111;
using namespace std;

struct data
{
    int x;
    int y;
    int direction;// 当前的方向
} robot[maxn];
int a[maxn][maxn];
// 四个方向：东，北，西，南，不要颠倒，抽象成二维坐标，想象坐标在移动的时候是如何变化的
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int A, B;

bool Move(int s, int t)
{
    int d = robot[s].direction;
    int x = robot[s].x;
    int y = robot[s].y;
    // 当前坐标的机器人移动走了
    a[x][y] = 0;
    for (int i = 0; i < t; i ++)
    {
        x = x + dir[d][0];
        y = y + dir[d][1];

        // 碰到边界
        if (x <= 0 || x > A || y <= 0 || y > B)
        {
            cout << "Robot " << s << " crashes into the wall" << endl;
            return true;
        }

        // 前进的位置有其他机器人，发生了相撞
        if (a[x][y])
        {
            cout << "Robot " << s << " crashes into robot " << a[x][y] << endl;
            return true;
        }
    }
    // 中间过程并没有意外发生。则当前机器人的坐标
    robot[s].x = x;
    robot[s].y = y;
    // 更新s编号机器人的位置
    a[x][y] = s;
    return false;
}

// s 为机器人的编号，t 为旋转的次数
bool Judge(int s, char c, int t)
{
    // 注意两个方向如何变化
    if (c == 'L')
        robot[s].direction = (robot[s].direction + t % 4) % 4;
    else if (c == 'R')
        robot[s].direction = (robot[s].direction - t % 4 + 4) % 4;
    else if (c == 'F') // 移动
        return Move(s, t);
    return false;
}

int main()
{
    int n, m, T, x, y;
    char c;
    scanf("%d", &T);
    while(T --)
    {
        // 注意两个都需要初始化
        mem(a, 0)
        memset(robot,0,sizeof(data) * maxn);
        // A 和 B 表示矩阵的长和宽
        // n 表示可以机器人的数量， m 表示操作指令的数目
        scanf("%d%d%d%d", &A, &B, &n, &m);
        for (int i = 1; i <= n; i ++)
        {
            // 矩阵的坐标以及指向的方向
            cin >> x >> y >> c;
            robot[i].x = x;
            robot[i].y = y;
            // 四个方向，方别赋值给不同的数字
            if (c == 'E')
                robot[i].direction = 0;
            else if (c == 'N')
                robot[i].direction = 1;
            else if (c == 'W')
                robot[i].direction = 2;
            else if (c == 'S')
                robot[i].direction = 3;
            // 记录下当前机器人的编号
            a[x][y] = i;
        }

        bool flag = false;
        for (int i = 1; i <= m; i ++)
        {
            cin >> x >> c >> y;
            if (!flag)
                // 只要找到一组碰壁或者是两个机器人相撞的，则都不继续判断
                flag = Judge(x, c, y);
        }
        if (!flag)
            cout << "OK" << endl;
    }
    return 0;
}
